package com.way.fileexplorer.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Locale;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.database.sqlite.SQLiteDiskIOException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Handler.Callback;
import android.os.Message;
import android.provider.MediaStore;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.way.fileexplorer.R;
import com.way.fileexplorer.activities.FileSearchResultActivity;
import com.way.fileexplorer.adapters.FileListAdapter;
import com.way.fileexplorer.adapters.QuickScanCursorAdapter;
import com.way.fileexplorer.adapters.SearchListAdapter;

public class FileUtil{
    private static final String TAG = "FileUtil";
    private static final boolean DBG = false;
    static ArrayList<File> mMultPaste = new ArrayList<File>();;
    static boolean mIsCut;
    static ProgressDialog mProgressDialog;
    static int mCopyedTotalSize = 0;
    static Handler mHandler = new Handler();
    static int mSection;
    static int mHasCopyedFileSize;
    public static final int FILE_ATTRIBUTE_MESSAGE = 100;
    public static final String CALC_FILE_NUM_KEY = "calc_file_num";
    public static final String CALC_FOLDER_NUM_KEY = "calc_folder_num";
    public static final String CALC_SIZE_KEY = "calc_size_num";
    public static boolean mCancelCopy;
    public static boolean mCancelDelete;
    static ProgressDialog deleteProgress = null;
    public static final int REFREAH_FILELIST = 101;
    private static String LOCATION_INTERNAL = "internal";
    private static String LOCATION_EXTERNAL = "external";

    private static final String INVALID_CHAR_CONTENT = "*\":/?|<>.";// bug 201927

    public static boolean delete(final File file, final Context context) {
        if (file == null) {
            return false;
        }
        if(!file.exists() || !file.canRead()){
            return false;
        }
        if (file.isDirectory()) {
            File[] list = file.listFiles();
            if (file.list().length > 0) {
                for (File f : list) {
                    delete(f, context);
                }
            }
        }
        if(!mCancelDelete){
            if(DBG) Log.d(TAG, "===================File path = " + file.getPath());
            // bug 201374 begin
            try {
//                if(file.getPath().startsWith(Environment.getInternalStoragePath().toString())) {
//                    context.getContentResolver().delete(MediaStore.Files.getContentUri(LOCATION_INTERNAL), MediaStore.Files.FileColumns.DATA+"=?", new String[]{file.getPath()});
//                } else {
                    context.getContentResolver().delete(MediaStore.Files.getContentUri(LOCATION_EXTERNAL), MediaStore.Files.FileColumns.DATA+"=?", new String[]{file.getPath()});
//                }
            } catch (SQLiteDiskIOException ioe) {
                Log.e(TAG, "com.sprd.fileexplorer delete file error!!SQLiteDiskIOException");
                mHandler.post(new Runnable() {

                    @Override
                    public void run() {
                        // TODO Auto-generated method stub
                        showMsg(context.getResources().getString(R.string.delete_fail_storage_full,file.getName()),context);
                    }

                });
                return false;
            }
            // bug 201374 end

            boolean deleteSucess = file.delete();            
            if(!deleteSucess && (file.isFile() || (file.isDirectory() && file.list().length == 0))){
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        // TODO Auto-generated method stub
                        showMsg(context.getResources().getString(R.string.delete_fail,file.getName()),context);
                    }
                    
                });
            }
            return file.delete();
        }else{
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    NotifyManager.getInstance(context).showToast(
                            context.getResources().getString(
                                    R.string.cancel_copy));
                    deleteProgress.dismiss();
                    return;
                }
            });
            return false;
        }
        
    }
    public static void deleteSingleFile(final File file, final Context context, final Handler handler){
        mCancelDelete = false;
        deleteProgress = new ProgressDialog(context);
        new Thread(new Runnable(){

            @Override
            public void run() {
                // TODO Auto-generated method stub
                ArrayList<File> files = new ArrayList<File>();
                files.add(file);
                int deleteFileSize = getTotalFileSize(files);
                if(deleteFileSize > 1024*1024){
                    mHandler.post(new Runnable(){
                     @Override
                     public void run() {
                         // TODO Auto-generated method stub
                         deleteProgress.setCancelable(false);
                         deleteProgress.setTitle(R.string.operate_delete);
                         deleteProgress.setMessage(context.getResources().getString(R.string.now_deleting));
                         deleteProgress.setButton(DialogInterface.BUTTON_NEGATIVE,
                                 context.getResources().getString(android.R.string.cancel), new DialogInterface.OnClickListener() {
                             public void onClick(DialogInterface dialog, int whichButton) {
                                 mCancelDelete = true;
                             }
                         });
                         deleteProgress.show();
                     }
                    });
                }
                delete(file, context);
                scanDir(context,file.getParentFile());// bug 201956
                mCancelDelete = false;
                handler.obtainMessage(REFREAH_FILELIST).sendToTarget();
                handler.post(new Runnable(){
                    @Override
                    public void run() {
                        // TODO Auto-generated method stub
                        if(deleteProgress != null && deleteProgress.isShowing()){
                            deleteProgress.dismiss();
                        }
                        showMsg(R.string.delete_finish,context);
                    }
                    
                }
                );
                
            }
            
        }).start();
       
    }
    
    
    public static void delete(final ArrayList<File> fileList, final Context context, final BaseAdapter adapter) {
        mCancelDelete = false;
        deleteProgress = new ProgressDialog(context);
        new Thread(new Runnable() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
               int deleteFileSize = getTotalFileSize(fileList);
               if(deleteFileSize > 1024*1024){
                   mHandler.post(new Runnable(){

                    @Override
                    public void run() {
                        // TODO Auto-generated method stub
                        deleteProgress.setCancelable(false);
                        deleteProgress.setTitle(R.string.operate_delete);
                        deleteProgress.setMessage(context.getResources().getString(R.string.now_deleting));
                        deleteProgress.setButton(DialogInterface.BUTTON_NEGATIVE,
                                context.getResources().getString(android.R.string.cancel), new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int whichButton) {
                                mCancelDelete = true;
                            }
                        });
                        deleteProgress.show();
                    }
                   });
               }
               for(File file:fileList){
                   delete(file, context);
               }
                scanAllFile(context);// bug 201956
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        // TODO Auto-generated method stub
                        if (adapter instanceof FileListAdapter) {
                            ((FileListAdapter) adapter).refresh();
                        } else if (adapter instanceof QuickScanCursorAdapter) {
                            ((QuickScanCursorAdapter) adapter).refresh();
                        }
                        if (deleteProgress != null
                                && deleteProgress.isShowing()) {
                            deleteProgress.dismiss();
                        }
                        showMsg(R.string.delete_finish,context);
                    }
                });
            }
        }).start();
    }

    public static File execute(File currentFile, File executeFile, Context context) {
        if (executeFile == null || currentFile == null) {
            throw new NullPointerException();
        }
        Slog.d("currentFile=" + currentFile.getPath() + "executeFile"
                + executeFile.getPath());
        if (!executeFile.canRead()) {
            NotifyManager.getInstance(context).showToast("Can't load it");
            return currentFile;
        }
        if (executeFile.isDirectory()) {
            return executeFile;
        }
        return currentFile;

    }

    public static void clear(final File file, final Context context) {
        mCancelDelete = false;
        ArrayList<File> files = new ArrayList<File>();
        files.add(file);
        int deleteFileSize = getTotalFileSize(files);
        if(deleteFileSize > 1024*1024){
            mHandler.post(new Runnable(){
             @Override
             public void run() {
                 // TODO Auto-generated method stub
                 deleteProgress = new ProgressDialog(context);
                 deleteProgress.setCancelable(false);
                 deleteProgress.setTitle(R.string.operate_delete);
                 deleteProgress.setMessage(context.getResources().getString(R.string.now_deleting));
                 deleteProgress.setButton(DialogInterface.BUTTON_NEGATIVE,
                         context.getResources().getString(android.R.string.cancel), new DialogInterface.OnClickListener() {
                     public void onClick(DialogInterface dialog, int whichButton) {
                         mCancelDelete = true;
                     }
                 });
                 deleteProgress.show();
             }
            });
        }
        if (file.exists() && file.isDirectory()) {
            File[] list = file.listFiles();
            if (file.list().length > 0) {
                for (File f : list) {
                    delete(f, context);
                }
            }
            scanFile(context, file);// bug 201956
        }
        mCancelDelete = false;
        if(deleteProgress != null && deleteProgress.isShowing()){
            deleteProgress.dismiss();
        }

    }

    public static void rename(File renameFile, FileListAdapter mAdapter, Context context) {
        buildRenameDialog(renameFile, mAdapter, null, context);
    }
    
    public static void rename(File renameFile, SearchListAdapter mAdapter, Context context) {
        buildRenameDialog(renameFile, mAdapter, null, context);
    }
    
    public static void rename(File renameFile, Context context) {
        buildRenameDialog(renameFile, null, null, context);
    }
    
    public static void rename(File renameFile, Uri renameFileUri, QuickScanCursorAdapter adapter, Context context) {
        buildRenameDialog(renameFile, adapter, renameFileUri, context);
    }

    public static void viewDetails(File file, Context context) {
        buildDetailDialog(file, context);
    }

    /**
     * @param date
     * @return
     */
    public static String getDateStr(long date) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss",
                Locale.getDefault());
        return format.format(date);
    }

    public static String getSize(File file) {
        if (file == null) {
            throw new NullPointerException();
        }
        if (file.canRead()) {
            return getFitSize(file.length());
        }
        return "0";
    }

    public static void mkdir(final File filePath, FileListAdapter fileAdapter, Context context) {
        buildNewDirDialog(filePath, fileAdapter, context);
    }
    
    public static void newfile(final File filePath, FileListAdapter fileAdapter, Context context) {
        buildNewFileDialog(filePath, fileAdapter, context);
    }

    /**
     * Convert long to String with B/KB/MB/GB. XXX: Suggest using getSize()
     * 
     * @param size
     * @return
     */
    public static String getFitSize(long size) {
        double tmp;
        if (size < 1024) {
            return size + "byte";
        } else {
            tmp = size / 1024.0;
            if (tmp < 1024) {
                return String.format("%.2f", tmp) + "KB";
            } else {
                tmp /= 1024;
                if (tmp < 1024) {
                    return String.format("%.2f", tmp) + "MB";
                } else {
                    return String.format("%.2f", tmp / 1024) + "GB";
                }
            }
        }
    }

    public static Bitmap readBitMap(String filePath, boolean isImage, Context context) {
        if(isImage){
            BitmapFactory.Options opt = new BitmapFactory.Options();
            opt.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(filePath, opt);
            //bug 198029 begin
            int lench= Math.max(opt.outWidth,opt.outHeight);
            int ss = (int) (lench / (float) 40);
            //int ss = (int) (opt.outHeight / (float) 45);
            //bug 198029 end
            if (ss <= 0)
                ss = 1;
            opt.inSampleSize = ss;
            opt.inJustDecodeBounds = false;
            opt.inPreferredConfig = Bitmap.Config.RGB_565;
            opt.inPurgeable = true;
            opt.inInputShareable = true;
            return BitmapFactory.decodeFile(filePath, opt);
        }else{
            PackageManager pm = context.getPackageManager();
            PackageInfo info = pm.getPackageArchiveInfo(filePath,
                    PackageManager.GET_ACTIVITIES);
            if (info != null) {
                ApplicationInfo appInfo = info.applicationInfo;
                appInfo.sourceDir = filePath;
                appInfo.publicSourceDir = filePath;
                Drawable drawable = appInfo.loadIcon(pm);
                BitmapDrawable bd = (BitmapDrawable) drawable;
                return bd.getBitmap();
            }else{
                return null;
            }

        }
    }


    public static void copy(Context context, final ArrayList<File> pathStr,
            boolean isCut) {
        mMultPaste.clear();
        mCopyedTotalSize = 0;
        mHasCopyedFileSize =0;
        mCancelCopy = false;
        new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                for(int i=0; i<pathStr.size(); i++){
                    if(pathStr.get(i).exists()){
                        mMultPaste.add(pathStr.get(i));
                    }
                }
                mCopyedTotalSize = getTotalFileSize(mMultPaste);
            }
        }).start();
        mIsCut = isCut;
    }

    public static void copy(Context context, final File file, boolean isCut) {
        mMultPaste.clear();
        mCancelCopy = false;
        mCopyedTotalSize = 0;
        mHasCopyedFileSize =0;
        new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                mMultPaste.add(file);
                mCopyedTotalSize = getTotalFileSize(mMultPaste);
            }
        }).start();
        mIsCut = isCut;
    }

    public static void clearPaste() {
        mMultPaste.clear();
    }

    public static void paste(final boolean isSdcard, final Context context, final File destDir,// bug 201956
            FileListAdapter fileAdapter) {
        long restSpace = isSdcard ? StorageUtil.getExternalStorage().getFreeSpace() : StorageUtil.getInternalStorage().getFreeSpace();
        if(mCopyedTotalSize > restSpace){
            mHandler.post(new Runnable(){
                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    Toast.makeText(context, R.string.no_enough_sapce,
                            Toast.LENGTH_SHORT).show();
                }
                
            });
            return;
        }
        mCancelCopy = false;
        if (mMultPaste.isEmpty()) {
            mHandler.post(new Runnable(){

                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    Toast.makeText(context, R.string.clipboard_empty,
                            Toast.LENGTH_SHORT).show();
                }
                
            });
        } else {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    mProgressDialog = new ProgressDialog(context);
                    mProgressDialog
                            .setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                    mProgressDialog.setTitle(R.string.now_copying);
                    mProgressDialog.setMax(mCopyedTotalSize);
                    mProgressDialog.setProgress(0);
                    mProgressDialog.setCanceledOnTouchOutside(false);
                    mProgressDialog.setCancelable(false);
                    mProgressDialog.setButton(
                            DialogInterface.BUTTON_NEGATIVE,
                            context.getResources().getString(
                                    android.R.string.cancel),
                            new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog,
                                        int whichButton) {
                                    mCancelCopy = true;

                                }
                            });
                    if (mCopyedTotalSize > 1024 * 1024) {
                        mProgressDialog.show();
                    }
                }
            });
            startCopy(mMultPaste, destDir, mCopyedTotalSize, context,
                    fileAdapter);
        }

    }


    public static int getTotalFileSize(ArrayList<File> selectedFiles) {
        int fileSize = 0;
        for (File file : selectedFiles) {
            if (file.isFile()) {
                fileSize += file.length();
            } else {
                try {
                    fileSize += getDirectorySize(file);
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

        }
        return fileSize;
    }

    public static long getDirectorySize(File f) throws IOException {
        long size = 0;
        File flist[] = f.listFiles();
        if (flist == null)
            return f.length();
        int length = flist.length;
        for (int i = 0; i < length; i++) {
            if (flist[i].isDirectory()) {
                size = size + getDirectorySize(flist[i]);
            } else {
                size = size + flist[i].length();
            }
        }
        return size;
    }

    public static void startCopy(ArrayList<File> from, final File destDir,// bug 201956
            long copyedFileSize, final Context context,
            final FileListAdapter fileAdapter) {
        ArrayList<File> deleteList = new ArrayList<File>();
        // bug 201956 begin
        String toPath = destDir.getPath();
        if (!destDir.isDirectory())
        // bug 201956 end
            return;
        for (final File copyedFile : from) {
            if(toPath.startsWith(copyedFile.getPath())){
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        // TODO Auto-generated method stub
                        showMsg(R.string.cannot_copy_to_itself, context);
                    }
                });
                continue;
            }
            if (copyedFile.isFile()) {
                String toFileStr = toPath + "/" + copyedFile.getName();
                File toFile = new File(toFileStr);
                if (toFile.exists()) {
                    if(copyedFile.getParent().equals(toPath)){
                        toFileStr = pathNameAppend(toFileStr, "-1");
                        while ((new File(toFileStr)).exists()) {
                            toFileStr = pathNameAppend(toFileStr, "-1");
                        }
                    }else{
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                // TODO Auto-generated method stub
                                showCopyWarnDialog(copyedFile, context, false);
                            }
                        });
                        synchronized (context) {
                            try {
                                context.wait();
                                if (mSection == 1) {
                                    toFileStr = pathNameAppend(toFileStr, "-1");
                                    while ((new File(toFileStr)).exists()) {
                                        toFileStr = pathNameAppend(toFileStr, "-1");
                                    }
                                }
                            } catch (InterruptedException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                        }
                    }
                    
                    toFile = new File(toFileStr);
                }

                try {
                   int result = copyFile(copyedFile, toFile, context);
                    if(result == 1){
                        break;
                    }
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            } else {
                try {
                    String toFileStr = toPath + "/" + copyedFile.getName();
                    File toFile = new File(toFileStr);
                    if (toFile.exists()) {
                        if(copyedFile.getParent().equals(toPath)){
                            toFileStr = pathNameAppend(toFileStr, "-1");
                            while ((new File(toFileStr)).exists()) {
                                toFileStr = pathNameAppend(toFileStr,
                                        "-1");
                            }
                        }else{
                            mHandler.post(new Runnable() {
                                @Override
                                public void run() {
                                    // TODO Auto-generated method stub
                                    showCopyWarnDialog(copyedFile, context, true);
                                }
                            });
                            synchronized (context) {
                                try {
                                    context.wait();
                                    if (mSection == 0) {
                                        delete(toFile,context);
                                    }
                                    if (mSection == 2) {
                                        toFileStr = pathNameAppend(toFileStr, "-1");
                                        while ((new File(toFileStr)).exists()) {
                                            toFileStr = pathNameAppend(toFileStr,
                                                    "-1");
                                        }
                                    }
                                } catch (InterruptedException e) {
                                    // TODO Auto-generated catch block
                                    e.printStackTrace();
                                }
                            }
                        }
                    }
                    if(mCancelCopy){
                        break;
                    }
                    copyDirectiory(copyedFile, toFileStr, context);
                //    mIsCopying = false;
                   
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if (mIsCut) {
                deleteList.add(copyedFile);
            }
        }
        if (mIsCut) {
            for(File f:deleteList){
                FileUtil.delete(f,context);
            }
            mMultPaste.clear();
        }
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                if(!mCancelCopy ){
                    if(mCopyedTotalSize > 0 && mHasCopyedFileSize >0){
                        showMsg(R.string.copy_finish,context);
                    }else if(mCopyedTotalSize ==0){
                        showMsg(R.string.copy_finish,context);
                    }
                }else{
                    showMsg(R.string.cancel_copy,context);
                }
                mCancelCopy = false;
                if(mProgressDialog != null && mProgressDialog.isShowing()){
                    mProgressDialog.dismiss();
                }
                scanDir(context,destDir);// bug 201956
                fileAdapter.refresh();
            }
        });
    }

    public static String getPathName(String path) {
        int index = path.lastIndexOf('/');
        if (index == -1 || index == 0)
            return path;
        return path.substring(index + 1);
    }

    public static String pathNameAppend(String path, String apd) {
        String name = getPathName(path);
        int i = name.lastIndexOf(".");
        if (i == -1 || i == 0)
            return path + apd;
        int l = path.lastIndexOf("/") + 1;
        return path.substring(0, l + i) + apd + path.substring(l + i);
    }

    public static void copyDirectiory(File sourceDir, String targetDir, Context context)
            throws IOException {
        Log.i(TAG, "copy Directory: sourceDir is" + sourceDir + " targetDir is"
                + targetDir);
        File[] file = sourceDir.listFiles();
        if(file == null){
            return;
        }
        if(mCancelCopy){
            return;
        }
        if((new File(targetDir)).mkdir()){
            mHasCopyedFileSize += (new File(targetDir)).length();
        }
        for (int i = 0; i < file.length; i++) {
            if (file[i].isFile()) {
                File sourceFile = file[i];
                File targetFile = new File(
                        new File(targetDir).getAbsolutePath() + File.separator
                                + file[i].getName());
                Log.i(TAG, "file [" + i + "] is file, copy it, sourceFile is "
                        + sourceFile + "and targetFile is" + targetFile);
                try {
                   if(copyFile(sourceFile, targetFile, context) == 1){
                      break;
                   }
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if (file[i].isDirectory()) {
                if(mCancelCopy){
                    break;
                }
                String dir1 = sourceDir.getPath() + "/" + file[i].getName();
                String dir2 = targetDir + "/" + file[i].getName();
                Log.i(TAG, "file [" + i
                        + "] is Directory, copy it, sourceDir is " + dir1
                        + "and targetFile is" + dir2 + "file[i] = " + file[i]);
                copyDirectiory(new File(dir1), dir2, context);
            }
        }
    }

    private static int BUFF_SIZE = 8192;
    private static int copyFile(final File src, File dst, Context context)
            throws InterruptedException {
        int ret = 0;
        FileInputStream fIn = null;
        FileOutputStream fOut = null;
        BufferedInputStream in = null;
        BufferedOutputStream out = null;
   //     mIsCopying = true;
        if (src == null || !src.exists() || !src.canRead()) {
            return -1;
        }
        if(mCancelCopy){
            return 1;
            
        }else{
            try {
                fIn = new FileInputStream(src);
                fOut = new FileOutputStream(dst);
                in = new BufferedInputStream(fIn, BUFF_SIZE);
                out = new BufferedOutputStream(fOut, BUFF_SIZE);
                byte[] bytes = new byte[BUFF_SIZE];
                int length;
                while ((length = in.read(bytes)) != -1) {
                    out.write(bytes, 0, length);
                    mHasCopyedFileSize += BUFF_SIZE;
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            // TODO Auto-generated method stub
                            if (mProgressDialog.isShowing()) {
                                mProgressDialog.setProgress(mHasCopyedFileSize);
                            }
                        }
                    });
                }
                out.flush();
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                try {
                    if (fIn != null)
                        fIn.close();
                    if (fOut != null)
                        fOut.close();
                    return ret;
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }

        return ret;
    }

    public static void getStorageStatus(Context context) {
        Intent intent = new Intent();
        intent.setAction("android.settings.INTERNAL_STORAGE_SETTINGS");
        context.startActivity(intent);
    }

    private static void buildNewDirDialog(final File filePath,
            final FileListAdapter adapter, final Context context) {
        View nameView = LayoutInflater.from(context).inflate(R.layout.edit_name, null); 
        Builder builder = new AlertDialog.Builder(context);
        final EditText fileNameText = (EditText)nameView.findViewById(R.id.name_editor);
        String newFileName = context.getResources().getString(R.string.menu_mkdir);
        int copy = 1;
        while ((new File(filePath.toString() +  "/" + newFileName)).exists()) {
            newFileName = pathNameAppend(context.getResources().getString(R.string.menu_mkdir), "-"+ (copy++));
        }
        fileNameText.setText(newFileName);
        fileNameText.requestFocus();
        
        builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener(){

			@Override
			public void onClick(DialogInterface dialog, int which) {

                // TODO Auto-generated method stub
			    Resources res = context.getResources();
                String fileName = fileNameText.getText().toString().trim();
                if (fileName == null || fileName.equals("")) {
                    showMsg(R.string.msg_file_input_empty,context);
                    return;
                }else if(!containsNoSpecialChars(fileName)){// bug 201927
                    showMsg(res.getString(
                            R.string.invalid_char,
                            INVALID_CHAR_CONTENT),context);// bug 201927
                    return ;
                }
                String folderPath = filePath.toString();
                if (folderPath != null) {
                    File newFolder = new File(folderPath + "/"
                            + fileName);
                    if (newFolder.exists()) {
                        showMsg(res.getString(
                                R.string.msg_file_input_repeat,
                                fileName),context);
                        keepDialog(dialog);
                    } else {
                        dialog.dismiss();
                        if (newFolder.mkdir()) {
                            adapter.refresh();
                            showMsg(res
                                    .getString(
                                            R.string.menu_mkdir_succeed,
                                            fileName),context);
                        } else {
                            if(!containsNoSpecialChars(fileName)){// bug 201927
                                showMsg(res.getString(
                                        R.string.invalid_char,
                                        INVALID_CHAR_CONTENT),context);// bug 201927
                            }else{
                                showMsg(res.getString(
                                        R.string.menu_mkdir_failed,
                                        fileName),context);
                                
                            }
                        }
                    }
                }				
			}
        	
        });
        builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener(){

			@Override
			public void onClick(DialogInterface dialog, int which) {
			    destroyDialog(dialog);
			}
        	
        });
        final AlertDialog dialog = builder.create();
        dialog.setTitle(R.string.menu_mkdir);
        dialog.setView(nameView);
        // bug 204103 begin
        dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
            @Override
            public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
                if ((keyCode == KeyEvent.KEYCODE_BACK) && (event.getAction() == KeyEvent.ACTION_UP)) {
                    destroyDialog(dialog);
                }
                return false;
            }
        });
        // bug 204103 end

        fileNameText.addTextChangedListener(new TextWatcher(){
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count,
                    int after) {
            }
            @Override
            public void onTextChanged(CharSequence newName, int start, int before,
                    int count) {
                if(newName.length() >= 84){
                    showMsg(R.string.length_limited,context);
                }
                final Button positiveButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
                if(positiveButton != null){
                	if(newName.length() <= 0){
                		positiveButton.setEnabled(false);
                	}else{
                		positiveButton.setEnabled(true);
                	}
                }
            }
            @Override
            public void afterTextChanged(Editable s) {
            }
        });
        dialog.getWindow().setSoftInputMode (WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
        dialog.show();
    }
    
    
    private static void buildNewFileDialog(final File filePath,
            final FileListAdapter adapter, final Context context) {
        View nameView = LayoutInflater.from(context).inflate(R.layout.edit_name, null); 
        Builder builder = new AlertDialog.Builder(context);        
        final EditText fileNameText = (EditText)nameView.findViewById(R.id.name_editor);
        String newFileName = context.getResources().getString(R.string.menu_newfile);
        int copy = 1;
        while ((new File(filePath.toString() +  "/" + newFileName + ".txt")).exists()) {
            newFileName = pathNameAppend(context.getResources().getString(R.string.menu_newfile), "-"+ (copy++));
        }
        fileNameText.setText(newFileName);
        fileNameText.requestFocus();
        builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener(){

			@Override
			public void onClick(DialogInterface dialog, int which) {

                // TODO Auto-generated method stub
                String fileName = fileNameText.getText().toString().trim();
                Resources res = context.getResources();
                if (fileName == null || fileName.equals("")) {
                    showMsg(R.string.msg_file_input_empty,context);
                    return;
                }else if(!containsNoSpecialChars(fileName)){// bug 201927
                    showMsg(res.getString(R.string.invalid_char,INVALID_CHAR_CONTENT),context);// bug 201927
                    return;
                }
                String folderPath = filePath.toString();
                if (folderPath != null) {
                    File newFile = new File(folderPath + "/"
                            + fileName+ ".txt");
                    
                    if (newFile.exists()) {
                        showMsg(res.getString(
                                R.string.msg_file_input_repeat,
                                fileName),context);
                        keepDialog(dialog);
                    } else {
                        destroyDialog(dialog);
                        try {
							if (newFile.createNewFile()) {
							    adapter.refresh();
							    showMsg(res
							            .getString(
							                    R.string.menu_newfile_succeed,
							                    fileName),context);
                                    } else {
                                        showMsg(res.getString(
                                                R.string.menu_newfile_failed,
                                                fileName), context);
                                    }
						} catch (NotFoundException e) {
							e.printStackTrace();
						} catch (IOException e) {
							e.printStackTrace();
						}
                    }
                }
			}
        	
        });
        builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener(){

			@Override
			public void onClick(DialogInterface dialog, int which) {
				destroyDialog(dialog);
			}
        	
        });
        final AlertDialog dialog = builder.create();
        dialog.setTitle(R.string.menu_newfile);
        dialog.setView(nameView);
        // bug 204103 begin
        dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
            @Override
            public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
                if ((keyCode == KeyEvent.KEYCODE_BACK) && (event.getAction() == KeyEvent.ACTION_UP)) {
                    destroyDialog(dialog);
                }
                return false;
            }
        });
        // bug 204103 end

        fileNameText.addTextChangedListener(new TextWatcher(){

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count,
                    int after) {
                // TODO Auto-generated method stub
            }

            @Override
            public void onTextChanged(CharSequence newName, int start, int before,
                    int count) {
                // TODO Auto-generated method stub
                if(newName.length() >= 84){
                    showMsg(R.string.length_limited,context);
                }
                
                final Button positiveButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
                if(positiveButton != null){
                	if(newName.length() <= 0){
                		positiveButton.setEnabled(false);
                	}else{
                		positiveButton.setEnabled(true);
                	}
                }
            }

            @Override
            public void afterTextChanged(Editable s) {
                // TODO Auto-generated method stub
                
            }
            
        });
        dialog.getWindow().setSoftInputMode (WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
        dialog.show();
    }

    private static void showCopyWarnDialog(File file, final Context context,
            boolean isDirectory) {
        AlertDialog.Builder copyWarnDialog = new AlertDialog.Builder(context);
        String[] items = context.getResources().getStringArray(
                isDirectory ? R.array.copydirWarning : R.array.copyfileWarning);
        copyWarnDialog.setTitle(
                context.getResources().getString(R.string.exist,
                        file.getName()));
        mSection = 0;
        copyWarnDialog.setSingleChoiceItems(items, 0, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
                mSection = whichButton;
            }
        });
        copyWarnDialog.setPositiveButton(android.R.string.ok,
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        synchronized (context) {
                            context.notify();
                        }
                    }
                });
        copyWarnDialog.show();
    }
    private static String extensionName;
    private static String subName;
    private static String newName;
    private static void buildRenameDialog(final File file,
            final BaseAdapter fileAdapter, final Uri fileUri, final Context context) {
        View nameView = LayoutInflater.from(context).inflate(R.layout.edit_name, null); 
        Builder builder = new AlertDialog.Builder(context);     
        
        final EditText fileNameText = (EditText)nameView.findViewById(R.id.name_editor);
        final String fileName = file.getName();
        final int dotIndex = fileName.lastIndexOf(".");
        if(file.isFile()){
            if(dotIndex > 0){
                extensionName = getExtensionName(fileName,dotIndex);
                subName = fileName.substring(0, dotIndex);
                fileNameText.setText(subName); 
            }else{
                fileNameText.setText(fileName);
            }
        }else if(file.isDirectory()){
            fileNameText.setText(fileName);
        }else{
            Log.i(TAG, "Is neither a file nor directory!");
        }
        fileNameText.requestFocus();       
        builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener(){

            @Override
            public void onClick(DialogInterface dialog, int which) {
                // bug 202957 begin
                if(!file.exists()) {
                    showMsg(R.string.file_no_exists,context);
                    return;
                }
                // bug 202957 end
                if(file.isFile()){
                    if(dotIndex<=0){
                        newName = fileNameText.getText().toString();
                    }else{
                        newName = fileNameText.getText()+extensionName; 
                    }
                }else if(file.isDirectory()){
                    newName = fileNameText.getText().toString().trim();
                }else{
                    Log.i(TAG, "Do nothing!");
                }
                
                Resources res = context.getResources();
                if (newName.equals("")) {
                    showMsg(R.string.msg_file_input_empty,context);
                    return;
                }
                File newFile = new File(file.getParent() + "/"
                        + newName);
                if (newFile.exists()) {
                    showMsg(res.getString(
                            R.string.msg_file_input_repeat,
                            newName),context);
                    keepDialog(dialog);
                } else {
                    destroyDialog(dialog);
                    // bug 201927 begin
                    if(!containsNoSpecialChars(newName)){
                        showMsg(res.getString(R.string.invalid_char,INVALID_CHAR_CONTENT),context);
                        return;
                    }
                    // bug 201927 end
                    if (file.renameTo(newFile)) {
                        scanDir(context,newFile.getParentFile());// bug 201956
                        if (fileAdapter != null
                                && fileAdapter instanceof FileListAdapter) {
                            ((FileListAdapter) fileAdapter)
                                    .refresh();
                        } else if (fileAdapter != null
                                && fileAdapter instanceof SearchListAdapter) {
                            if (((SearchListAdapter) fileAdapter)
                                    .getInSearchUi()) {
                                ((FileSearchResultActivity) context)
                                        .searchFile();
                            } else {
                                File file = ((SearchListAdapter) fileAdapter)
                                        .getCurrentPath();
                                ((SearchListAdapter) fileAdapter)
                                        .refresh(file);
                            }
                        }else if (fileAdapter != null
                                    && fileAdapter instanceof QuickScanCursorAdapter) {
                                ((QuickScanCursorAdapter) fileAdapter)
                                        .refresh();
                        }
                        showMsg(R.string.operate_rename_succeed,context);
                    } else {
                        // bug 201927 begin
                        showMsg(res.getString(
                                R.string.operate_rename_failed,
                                file.getName()),context);
                        // bug 201927 end
                    }

                }

            
            }
        	
        });
        builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener(){

			@Override
			public void onClick(DialogInterface dialog, int which) {
			    destroyDialog(dialog);
			}
        	
        });
        
        final AlertDialog dialog = builder.create();
        dialog.setTitle(R.string.operate_rename);
        dialog.setView(nameView);
        // bug 204103 begin
        dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
            @Override
            public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
                if ((keyCode == KeyEvent.KEYCODE_BACK) && (event.getAction() == KeyEvent.ACTION_UP)) {
                    destroyDialog(dialog);
                }
                return false;
            }
        });
        // bug 204103 end

        fileNameText.addTextChangedListener(new TextWatcher(){

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count,
                    int after) {
                // TODO Auto-generated method stub
            }

            @Override
            public void onTextChanged(CharSequence newName, int start, int before,
                    int count) {
                // TODO Auto-generated method stub
                if(newName.length() >= 84){
                    showMsg(R.string.length_limited,context);
                }
                final Button positiveButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
                if(positiveButton != null){
                	if(newName.length() <= 0){
                		positiveButton.setEnabled(false);
                	}else{
                		positiveButton.setEnabled(true);
                	}
                }
            }

            @Override
            public void afterTextChanged(Editable s) {
                // TODO Auto-generated method stub
                
            }
            
        });
       
        dialog.getWindow().setSoftInputMode (WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
        dialog.show();
    }
    
    private static String  getExtensionName(String fileName,int dotIndex){
        if(fileName != null && (fileName.length() > 0)){
            if((dotIndex > -1) && (dotIndex < (fileName.length() - 1))){
                return fileName.substring(dotIndex);
            }
        }
        return fileName;
    }

    private static void buildDetailDialog(final File file, Context context) {
        Resources res = context.getResources();
        String fileMessage = res
                .getString(file.isFile() ? R.string.operate_viewdetails_type_file
                        : R.string.operate_viewdetails_type_folder)
                + "\n"
                +res.getString(R.string.operate_viewdetails_path,
                        file.getParent())+ "\n"
                + res.getString(R.string.operate_viewdetails_date,
                        FileUtil.getDateStr(file.lastModified()));
        AlertDialog.Builder deteilDialog = new AlertDialog.Builder(context);
        TextView detailView = new TextView(context);
        detailView.setTextColor(Color.BLACK);
        detailView.setPadding(20, 0, 10, 0);
        detailView.setTextSize(18);
        deteilDialog.setView(detailView);
        if (file.isDirectory()) {
            detailView.setText(fileMessage + "\n"
                    + res.getString(R.string.caculating) + "\n"
                    + res.getString(R.string.operate_viewdetails_size,
                            FileUtil.getFitSize(file.length())) + "\n"
                    + (file.canRead() ? res.getString(R.string.operate_viewdetails_canread) : res.getString(R.string.operate_viewdetails_can_not_read)) + "\n"
                    + (file.canRead() ? res.getString(R.string.operate_viewdetails_can_write) : res.getString(R.string.operate_viewdetails_can_not_write)) + "\n" 
                    + (file.isHidden() ? res.getString(R.string.operate_viewdetails_hide) : res.getString(R.string.operate_viewdetails_not_hide)));
            updateAttribute(deteilDialog, file, fileMessage, detailView, context);
        } else {
            detailView.setText(fileMessage
                    + "\n"
                    + res.getString(R.string.operate_viewdetails_size,
                            FileUtil.getFitSize(file.length())) + "\n"
                    + (file.canRead() ? res.getString(R.string.operate_viewdetails_canread) : res.getString(R.string.operate_viewdetails_can_not_read)) + "\n"
                    + (file.canRead() ? res.getString(R.string.operate_viewdetails_can_write) : res.getString(R.string.operate_viewdetails_can_not_write)) + "\n" 
                    + (file.isHidden() ? res.getString(R.string.operate_viewdetails_hide) : res.getString(R.string.operate_viewdetails_not_hide)));
        }
        deteilDialog
                .setTitle(file.getName())
                .setPositiveButton(R.string.dialog_back,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog,
                                    int which) {

                            }
                        }).show();
    }

    private static void updateAttribute(final AlertDialog.Builder dialog,
            final File file, final CharSequence headStr, final TextView textView, final Context context) {
        Handler handler = new Handler(context.getMainLooper(), new Callback() {

            @Override
            public boolean handleMessage(Message msg) {
                switch (msg.what) {
                case FILE_ATTRIBUTE_MESSAGE:
                    Resources res = context.getResources();
                    Bundle data = msg.getData();
                    long fileNum = data.getLong(CALC_FILE_NUM_KEY);
                    long folderNum = data.getLong(CALC_FOLDER_NUM_KEY);
                    String size = data.getString(CALC_SIZE_KEY);
                    textView.setText(headStr
                            + "\n"
                            + context.getResources().getString(
                                    R.string.operate_folder_attribute, fileNum,
                                    folderNum, size) + "\n"
                                    + (file.canRead() ? res.getString(R.string.operate_viewdetails_canread) : res.getString(R.string.operate_viewdetails_can_not_read)) + "\n"
                                    + (file.canRead() ? res.getString(R.string.operate_viewdetails_can_write) : res.getString(R.string.operate_viewdetails_can_not_write)) + "\n" 
                                    + (file.isHidden() ? res.getString(R.string.operate_viewdetails_hide) : res.getString(R.string.operate_viewdetails_not_hide)));
                    break;
                }
                return false;
            }
        });
        CalcFileAttribute calc = new CalcFileAttribute(handler, file);
        calc.start();
    }

    public static class CalcFileAttribute extends Thread {

        private Handler mHandler;

        private File mFile;

        long[] calcRet = new long[3];

        public CalcFileAttribute(Handler handler, File file) {
            super();
            this.mHandler = handler;
            mFile = file;
        }

        @Override
        public void run() {
            long startTime = System.currentTimeMillis();
            Stack<File> stack = new Stack<File>();
            if (mFile != null && mFile.exists()) {
                stack.push(mFile);
            }
            while (!stack.empty()) {
                File file = stack.pop();
                if (!file.exists()) {
                    break;
                }
                if (file.isFile()) {
                    calcRet[0]++;
                    calcRet[2] += file.length();
                    continue;
                } else {
                    calcRet[1]++;
                    calcRet[2] += file.length();
                    File[] list = file.listFiles();
                    if (list != null) {
                        for (File f : list) {
                            stack.add(f);
                        }
                    }
                }
                long tmp = System.currentTimeMillis();
                if (tmp - startTime > 1000) {
                    sendMessage();
                    startTime = tmp;
                }
            }
            if (mFile.isDirectory()) {
                calcRet[1]--;
            }
            sendMessage();
        }

        private void sendMessage() {
            Message msg = mHandler.obtainMessage();
            msg.what = FILE_ATTRIBUTE_MESSAGE;
            Bundle data = new Bundle();
            data.putLong(CALC_FILE_NUM_KEY, calcRet[0]);
            data.putLong(CALC_FOLDER_NUM_KEY, calcRet[1]);
            data.putString(CALC_SIZE_KEY, FileUtil.getFitSize(calcRet[2]));
            msg.setData(data);
            mHandler.sendMessage(msg);
        }

    }

    private static void showMsg(String msg, Context context) {
        Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
    }

    private static void showMsg(int resId, Context context) {
        Toast.makeText(context, resId, Toast.LENGTH_SHORT).show();
    }
    private static String removeSuffix(File file) {
        if (file == null || !file.exists() || file.isDirectory()) {
            return null;
        }
        String fileName = file.getName();
        if (fileName.equals("") || fileName.endsWith(".")) {
            return null;
        }
        int index = fileName.lastIndexOf(".");
        if (index > 0) {
            return fileName.substring(0,index);
        } else {
            return fileName;
        }
    }
    
    private static void keepDialog(DialogInterface dialog) {
        try {
            if (dialog != null) {
                Field field = dialog.getClass().getSuperclass()
                        .getDeclaredField("mShowing");
                if (field != null) {
                    field.setAccessible(true);
                    field.set(dialog, false);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
               
    private static void destroyDialog(DialogInterface dialog) {
        try {
            if (dialog != null) {
                Field field = dialog.getClass().getSuperclass()
                        .getDeclaredField("mShowing");
                if (field != null) {
                    field.setAccessible(true);
                    field.set(dialog, true);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // bug 201956 begin
    private static void scanFile(Context context, File file) {
        Log.i(TAG,"send broadcast to scan file");
        context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file)));
    }

    private static void scanDir(Context context, File dir) {
        Log.i(TAG,"send broadcast to scan dir = " + dir);
        context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.fromFile(dir)));
    }

    private static void scanAllFile(Context context){
        Log.i(TAG,"send broadcast to scan all file ");
        File internalPath = StorageUtil.getInternalStorage();
        File externalPath = StorageUtil.getExternalStorage();
        context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.fromFile(internalPath)));
        if(StorageUtil.getExternalStorageState().equals("mounted")){
            context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.fromFile(externalPath)));
        }
    }
    // bug 201956 end


    // bug 201927 begin
    private static final String REGEX_SPECIAL_CHAR = "[^*\"\\\\/?|<>$]{1,}";

    /**
     * Check whether the file name has special character *"\/?<> or starts with .
     * @param fileName
     * @return true if it matches or does not return false
     */
    private static boolean containsNoSpecialChars(String fileName) {
        Pattern p = Pattern.compile(REGEX_SPECIAL_CHAR);
        Matcher m = p.matcher(fileName);
        Log.i(TAG, fileName + " matches = " + m.matches());
        return m.matches() && (!fileName.startsWith("."));// TODO can startsWith(".") be treated by regular expression
    }
    // bug 201927 end

}
